<script lang="ts">
  import type { BoardInfo } from "$lib/api/board/board";
  import type { MemberInfo } from "$lib/api/board/board_member";
  import { drawStore } from "./store.svelte";
  import {
    type Node as FlowNode,
    useSvelteFlow,
    SvelteFlow,
    Background,
    Controls,
    MiniMap,
    Panel,
    ConnectionMode,
    type XYPosition,
    type NodeTypes,
    type EdgeTypes,
    BackgroundVariant,
  } from "@xyflow/svelte";
  import { watchResize } from "svelte-watch-resize";
  import CommonTools from "./tools/CommonTools.svelte";
  import { listen } from "@tauri-apps/api/event";
  import type { AllNotice } from "$lib/api/notice_type";

  import "@xyflow/svelte/dist/style.css";
  import "./flow.css";
  import {
    initNodes,
    nodes,
    edges,
    removeEdges,
    removeNodes,
    moveNodes,
    createDropNode,
    initEdges,
    onCreateEdge,
    sendMyMousePositon,
  } from "./DrawFlowHelp.svelte";
  import NodeIndex from "./tools/NodeIndex.svelte";
  import DrawEdge from "./edges/DrawEdge.svelte";
  import EditEdgeTool from "./edges/EditEdgeTool.svelte";
  import CreateSvgNodeModal from "./modal/CreateSvgNodeModal.svelte";
  import MultiNodeTool from "./tools/MultiNodeTool.svelte";
  import { MousePointer2 } from "lucide-svelte";

  import BasicRectangleNode from "$lib/components/draw/nodes/basic/BasicRectangleNode.svelte";
  import BasicEllipseNode from "$lib/components/draw/nodes/basic/BasicEllipseNode.svelte";
  import BasicSvgNode from "$lib/components/draw/nodes/basic/BasicSvgNode.svelte";
  import BasicImageNode from "$lib/components/draw/nodes/basic/BasicImageNode.svelte";
  import BasicLinkNode from "$lib/components/draw/nodes/basic/BasicLinkNode.svelte";
  import TextNode from "$lib/components/draw/nodes/common/TextNode.svelte";
  import UnkwownNode from "$lib/components/draw/nodes/common/UnkwownNode.svelte";
  import LlmAskNode from "$lib/components/draw/nodes/llm/LlmAskNode.svelte";
  import LlmAnswerNode from "$lib/components/draw/nodes/llm/LlmAnswerNode.svelte";
  import DevelopIssueNode from "$lib/components/draw/nodes/develop/DevelopIssueNode.svelte";
  import DevelopMermaidNode from "$lib/components/draw/nodes/develop/DevelopMermaidNode.svelte";

  import dayjs from "dayjs";
  import AskTool from "./tools/AskTool.svelte";
  import CreateDevelopIssueNodeModal from "./modal/develop/CreateDevelopIssueNodeModal.svelte";
  import CreateImageNodeModal from "./modal/CreateImageNodeModal.svelte";
  import EditLinkNodeModal from "./modal/EditLinkNodeModal.svelte";
  import EditMermaidNodeModal from "./modal/develop/EditMermaidNodeModal.svelte";
  import ChatPanel from "./chat/ChatPanel.svelte";

  interface Props {
    boardInfo: BoardInfo;
    myMember: MemberInfo;
    drawId: string;
    heightClass: string;
  }

  let props: Props = $props();

  const nodeTypes = {
    UnkwownNode: UnkwownNode,
    BasicRectangleNode: BasicRectangleNode,
    BasicEllipseNode: BasicEllipseNode,
    BasicSvgNode: BasicSvgNode,
    BasicImageNode: BasicImageNode,
    BasicLinkNode: BasicLinkNode,
    TextNode: TextNode,
    LlmAskNode: LlmAskNode,
    LlmAnswerNode: LlmAnswerNode,
    DevelopIssueNode: DevelopIssueNode,
    DevelopMermaidNode: DevelopMermaidNode,
  } as unknown as NodeTypes;

  const edgeTypes = {
    DrawEdge: DrawEdge,
  } as unknown as EdgeTypes;

  const { screenToFlowPosition, flowToScreenPosition, fitView } =
    useSvelteFlow();

  let dropPosition = $state(null as null | XYPosition);

  let showAskInput = $derived(() => {
    if (drawStore.readOnly) {
      return false;
    }
    if (drawStore.selectNodeIdList.length != 1) {
      return false;
    }
    const selNodeId = drawStore.selectNodeIdList[0];
    const node = drawStore.nodeList.find((item) => item.node_id == selNodeId);
    if (node == undefined) {
      return false;
    }
    if (node.content.LlmAskContent == undefined) {
      return false;
    }
    //检查是否有回答节点
    const edge = drawStore.edgeList.find(
      (item) =>
        item.edge_key.from_node_id == node.node_id &&
        drawStore.nodeList.findIndex(
          (item2) => item2.node_id == item.edge_key.to_node_id,
        ) != -1,
    );
    return edge == undefined;
  });

  if (drawStore.drawId == props.drawId) {
    drawStore.loadMemberList();
  }

  function calcUserPosition(x: number, y: number) {
    const position = flowToScreenPosition({ x, y });
    if (position.y < 50) {
      return "display:none;";
    }
    return `top:${position.y}px;left:${position.x}px;`;
  }

  $effect(() => {
    drawStore.init(props.boardInfo, props.myMember, props.drawId);
  });

  $effect(() => {
    return () => {
      drawStore.reset();
    };
  });

  $effect(() => {
    initNodes();
  });

  $effect(() => {
    initEdges();
  });

  $effect(() => {
    const unListen = listen<AllNotice>("notice", (ev) => {
      const payload = ev.payload;
      if (payload.BoardNotice != undefined) {
        drawStore.processBoardNotice(payload.BoardNotice);
      }
    });
    return () => {
      unListen.then((fn) => fn());
    };
  });

  $effect(() => {
    if (drawStore.drawId != "") {
      //drawId变化时重新fitView
      setTimeout(() => {
        fitView();
      }, 500);
    }
  });

  $effect(() => {
    const t = setInterval(() => {
      const nowTime = dayjs().valueOf();
      const tmpList = drawStore.userPositionList.filter(
        (item) => nowTime - item.timeStamp < 60 * 1000,
      );
      if (tmpList.length != drawStore.userPositionList.length) {
        drawStore.userPositionList = tmpList;
      }
    }, 10 * 1000);
    return () => {
      clearInterval(t);
    };
  });
</script>

{#if nodeTypes != undefined && edgeTypes != undefined}
  <main
    class={`${props.heightClass} relative`}
    use:watchResize={() => fitView()}
  >
    <SvelteFlow
      {nodes}
      {edges}
      {nodeTypes}
      {edgeTypes}
      connectionMode={ConnectionMode.Loose}
      fitView={true}
      panOnDrag={drawStore.curToolInfo == "move"}
      deleteKey={["Backspace", "Delete"]}
      onmousemove={(e) => {
        sendMyMousePositon(e.clientX, e.clientY, screenToFlowPosition);
      }}
      ondelete={({ nodes, edges }) => {
        removeEdges(edges);
        removeNodes(nodes);
      }}
      onedgecreate={(conn) => onCreateEdge(conn)}
      on:nodedragstop={(
        e: CustomEvent<{ targetNode: FlowNode | null; nodes: FlowNode[] }>,
      ) => {
        if (e.detail.targetNode != null) {
          moveNodes([e.detail.targetNode]);
        }
        if (e.detail.nodes.length > 0) {
          moveNodes(e.detail.nodes);
        }
      }}
      onconnectstart={() => {
        drawStore.inConnect = true;
        drawStore.curToolInfo = "move";
      }}
      onconnectend={() => (drawStore.inConnect = false)}
      ondragover={(e) => {
        e.preventDefault();
        if (e.dataTransfer) {
          e.dataTransfer.effectAllowed = "move";
        }
      }}
      ondrop={(e) => {
        if (
          typeof drawStore.curToolInfo == "object" &&
          drawStore.curToolInfo.showModal == false
        ) {
          createDropNode(e.clientX, e.clientY, screenToFlowPosition);
        } else {
          dropPosition = screenToFlowPosition({ x: e.clientX, y: e.clientY });
        }
      }}
    >
      <Background variant={BackgroundVariant.Cross} />
      {#if drawStore.selectNodeIdList.length >= 2}
        <Panel position="top-right">
          <MultiNodeTool />
        </Panel>
      {:else if drawStore.selectNodeIdList.length == 0 && drawStore.selectEdgeKeyList.length == 1}
        <Panel position="top-right">
          <EditEdgeTool />
        </Panel>
      {:else}
        <Controls
          showLock={false}
          position="top-right"
          orientation="horizontal"
        />
      {/if}

      <MiniMap
        nodeStrokeWidth={3}
        pannable={true}
        zoomable={true}
        zoomStep={1}
        position="bottom-left"
      />
      <Panel position="top-left">
        {#if drawStore.readOnly == false}
          <NodeIndex />
        {/if}
      </Panel>
      <Panel position="top-center">
        <CommonTools />
      </Panel>
      {#if showAskInput()}
        <Panel position="bottom-center">
          <AskTool />
        </Panel>
      {/if}
      <Panel position="bottom-right">
        <ChatPanel />
      </Panel>
    </SvelteFlow>
  </main>
{/if}

<div class="absolute -left-[10000px]">
  {#if typeof drawStore.curToolInfo == "object" && drawStore.curToolInfo.content.BasicSvgContent != null && dropPosition != null}
    <CreateSvgNodeModal
      width={drawStore.curToolInfo.defaultWidth}
      height={drawStore.curToolInfo.defaultHeight}
      position={dropPosition}
      onClose={() => {
        dropPosition = null;
        drawStore.curToolInfo = "move";
      }}
    />
  {/if}

  {#if typeof drawStore.curToolInfo == "object" && drawStore.curToolInfo.content.DevelopIssueContent != null && dropPosition != null}
    <CreateDevelopIssueNodeModal
      width={drawStore.curToolInfo.defaultWidth}
      height={drawStore.curToolInfo.defaultHeight}
      position={dropPosition}
      onClose={() => {
        dropPosition = null;
        drawStore.curToolInfo = "move";
      }}
    />
  {/if}

  {#if typeof drawStore.curToolInfo == "object" && drawStore.curToolInfo.content.DevelopMermaidContent != null && dropPosition != null}
    <EditMermaidNodeModal
      width={drawStore.curToolInfo.defaultWidth}
      height={drawStore.curToolInfo.defaultHeight}
      position={dropPosition}
      onClose={() => {
        dropPosition = null;
        drawStore.curToolInfo = "move";
      }}
    />
  {/if}

  {#if typeof drawStore.curToolInfo == "object" && drawStore.curToolInfo.content.BasicImageContent != null && dropPosition != null}
    <CreateImageNodeModal
      width={drawStore.curToolInfo.defaultWidth}
      height={drawStore.curToolInfo.defaultHeight}
      position={dropPosition}
      onClose={() => {
        dropPosition = null;
        drawStore.curToolInfo = "move";
      }}
    />
  {/if}

  {#if typeof drawStore.curToolInfo == "object" && drawStore.curToolInfo.content.BasicLinkContent != null && dropPosition != null}
    <EditLinkNodeModal
      width={drawStore.curToolInfo.defaultWidth}
      height={drawStore.curToolInfo.defaultHeight}
      position={dropPosition}
      onClose={() => {
        dropPosition = null;
        drawStore.curToolInfo = "move";
      }}
    />
  {/if}

  {#each drawStore.userPositionList as userPosition}
    <div
      class="fixed flex gap-2"
      style={calcUserPosition(userPosition.x, userPosition.y)}
    >
      <MousePointer2 />{drawStore.boardMemberList.find(
        (item) => item.member_user_id == userPosition.memberUserId,
      )?.member_display_name ?? ""}
    </div>
  {/each}
</div>
